package org.gap.jseed;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import org.gap.jseed.util.ClassUtil;
import org.gap.jseed.util.FieldExtractor;

public abstract class AbstractClassInvocationHandler implements InvocationHandler {
	
	private static final String INVOCATION_FIELD = "_invocation";

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		String name = method.getName();
		
		if (name.equals("equals") && oneArgs(args)) {
			return assertAndInvokeEquals(proxy, args[0]);
		} else if (name.equals("toString") && noArgs(args)) {
			 return invokeToString(proxy);
		} else if (name.equals("hashCode") && noArgs(args)) {
			return invokeHashCode(proxy);
		} else {
			return invokeMethod(proxy, method, args);
		}
	}

	protected boolean oneArgs(Object[] args) {
		return args.length == 1;
	}

	protected boolean noArgs(Object[] args) {
		return args.length == 0;
	}
	
	private Object assertAndInvokeEquals(Object proxy, Object other) {
		return ClassUtil.equalClass(proxy, other) ? 
				invokeEquals(this, getOthersMatchingInvocationHandler(other)):
				false;
	}

	private InvocationHandler getOthersMatchingInvocationHandler(Object otherObject) {
		return (InvocationHandler)FieldExtractor.extract(otherObject, INVOCATION_FIELD);
	}

	protected boolean invokeEquals(InvocationHandler proxy, InvocationHandler other) {
		return proxy == other;
	}
	
	protected int invokeHashCode(Object proxy) {
		return hashCode();
	}
	
	protected String invokeToString(Object proxy) {
		return toString();
	}
	
	public abstract Object invokeMethod(Object proxy, Method method, Object[] args);
	
}
